
`include "defines.v"

module csrs(
    input  wire clk,
	input  wire rst,

	input wire ecall_en,
	input wire mret_en,
	input wire time_intr_en,
	input wire [`REG_BUS]wb_pc,
	//input wire [`REG_BUS]wb_next_pc,
	input wire clint_raise_interruption,
	output wire [`REG_BUS]mtvec_dest, 
	output wire [`REG_BUS]mepc_dest,
	output wire mstatus_mie,
	output wire mie_mtie,
	
	input  wire  [11  : 0] csr_w_addr,
	input  wire  [`REG_BUS] csr_w_data,
	input  wire 		  csr_w_ena,
	
	input  wire  [11  : 0] csr_r_addr,
	output reg   [`REG_BUS] csr_r_data,
	input  wire 		  csr_r_ena,
	
	
	//difftest
	output wire [`REG_BUS]mstatus_o,
	output wire [`REG_BUS]sstatus_o,
	output wire [`REG_BUS]mtvec_o,
	output wire [`REG_BUS]mepc_o,
	output wire [`REG_BUS]mcause_o,
	output wire [`REG_BUS]mip_o,
	output wire [`REG_BUS]mie_o,
	output wire [`REG_BUS]mscratch_o

    );
	//wire writable = csr_w_ena && (csr_w_addr[11:10] != 2'b11);


	assign mstatus_o = mstatus;
	assign sstatus_o = sstatus;
	assign mtvec_o = mtvec;
	assign mepc_o = mepc;
	assign mcause_o = mcause;
	assign mip_o = mip;
	assign mie_o = mie;
	assign mscratch_o = mscratch;
	assign mstatus_mie = mstatus_l[3];
	assign mie_mtie = mie[7];


	//mcycle
	reg [`REG_BUS] 	mcycle;
	always @(posedge clk) 
	begin
		if ( rst == 1'b1 ) begin
			mcycle <= `ZERO_WORD;
		end
		else if ((csr_w_ena == 1'b1) && (csr_w_addr[11:10] != 2'b11) && (csr_w_addr == 12'hb00)) begin	
			mcycle <= csr_w_data;
		end
		else begin
			mcycle <= mcycle + 1;
		end
	end

	//mstatus
	reg [62:0] mstatus_l;
	wire mstatus_sd;
	assign mstatus_sd = ((mstatus_l[16:15]==2'b11) || (mstatus_l[14:13]==2'b11));
	wire [`REG_BUS] mstatus;
	assign mstatus = {mstatus_sd,mstatus_l};
	always @(posedge clk)
	begin
		if (rst == 1'b1) begin
			mstatus_l <= 0;
			mstatus_l[3] <= 1'b1;    //MIE
		end
		else if (ecall_en == 1'b1) begin
			mstatus_l[7] <= mstatus_l[3];  //MPIE<-MIE
			mstatus_l[3] <= 1'b0;
			mstatus_l[12:11] <= 2'b11;
		end
		else if (mret_en == 1'b1) begin
			mstatus_l[3] <= mstatus_l[7];
			mstatus_l[7] <= 1'b1;
			mstatus_l[12:11] <= 2'b00;
		end
		else if (time_intr_en == 1'b1) begin
			mstatus_l[7] <= mstatus_l[3];  //MPIE<-MIE
			mstatus_l[3] <= 1'b0;
			mstatus_l[12:11] <= 2'b11;
		end
		else if ((csr_w_ena == 1'b1) && (csr_w_addr[11:10] != 2'b11) && (csr_w_addr == 12'h300)) begin
			mstatus_l <= csr_w_data[62:0];
		end
		else begin
			mstatus_l <= mstatus_l;
		end
		//mstatus[12:11] <= 2'b11;  //MPP
	end

	//sstatus
	wire [`REG_BUS] 	sstatus;
	assign sstatus = {mstatus_sd,mstatus_l} & 64'h80000003000de112;

	//mtvec
	reg [`REG_BUS] mtvec;
	always @(posedge clk)
	begin
		if (rst == 1'b1) begin
			mtvec <= `ZERO_WORD;
		end
		else if ((csr_w_ena == 1'b1) && (csr_w_addr[11:10] != 2'b11) && (csr_w_addr == 12'h305)) begin
			mtvec <= csr_w_data;
		end
		else begin
			mtvec <= mtvec;
		end
		mtvec[1:0] <= 2'b00;  
	end

	//mepc
	reg [`REG_BUS]mepc;
	always @(posedge clk)
	begin
		if (rst == 1'b1) begin
			mepc <= `ZERO_WORD;
		end
		else if (ecall_en == 1'b1) begin
			mepc <= wb_pc;
		end
		else if (time_intr_en == 1'b1) begin
			mepc <= wb_pc;
		end
		else if ((csr_w_ena == 1'b1) && (csr_w_addr[11:10] != 2'b11) && (csr_w_addr == 12'h341)) begin
			mepc <= csr_w_data;
		end
		else begin
			mepc <= mepc;
		end
	end
	/*
	//mepc
	reg [61:0] mepc_h;
	wire [1:0] mepc_l;
	assign mepc_l  = 2'b0;
	wire [`REG_BUS]mepc;
	assign mepc = {mepc_h,mepc_l};
	always @(posedge clk)
	begin
		if (rst == 1'b1) begin
			mepc_h <= 62'b0;
		end
		else if (ecall_en == 1'b1) begin
			mepc_h <= wb_pc[63:2];
		end
		else if (time_intr_en == 1'b1) begin
			mepc_h <= wb_pc[63:2];
		end
		else if ((csr_w_ena == 1'b1) && (csr_w_addr[11:10] != 2'b11) && (csr_w_addr == 12'h341)) begin
			mepc_h <= csr_w_data[63:2];
		end
		else begin
			mepc_h <= mepc_h;
		end
	end
	*/

	//mcause
	reg [`REG_BUS] mcause;
	always @(posedge clk)
	begin
		if (rst == 1'b1) begin
			mcause <= `ZERO_WORD;
		end
		else if (ecall_en == 1'b1) begin
			mcause[63] <= 0;
			mcause[62:0] <= {{59{1'b0}},4'b1011};
		end
		else if (time_intr_en == 1'b1) begin
			mcause[63] <= 1;
			mcause[62:0] <= {{59{1'b0}},4'b0111};
		end
		else if ((csr_w_ena == 1'b1) && (csr_w_addr[11:10] != 2'b11) && (csr_w_addr == 12'h342)) begin
			mcause <= csr_w_data;
		end
		else begin
			mcause <= mcause;
		end
	end

	//mip
	reg [`REG_BUS] mip;
	always @(posedge clk)
	begin
		if (rst == 1'b1) begin
			mip <= `ZERO_WORD;
		end
		else begin
			if (time_intr_en == 1'b1) begin
				mip[7]<=1'b1;  //MTIP
			end	
			if ((csr_w_ena == 1'b1) && (csr_w_addr[11:10] != 2'b11) && (csr_w_addr == 12'h344)) begin
			mip <= csr_w_data;
			end
			else begin
				mip <= mip;
			end
		end
	end

	//mie
	reg [`REG_BUS] mie;
	always @(posedge clk)
	begin
		if (rst == 1'b1) begin
			mie <= `ZERO_WORD;
		end
		else if ((csr_w_ena == 1'b1) && (csr_w_addr[11:10] != 2'b11) && (csr_w_addr == 12'h304)) begin
			mie <= csr_w_data;
		end
		else begin
			mie <= mie;
		end
	end

	//mscracth
	reg [`REG_BUS] 	mscratch;
	always @(posedge clk) 
	begin
		if ( rst == 1'b1 ) begin
			mscratch <= `ZERO_WORD;
		end
		else if ((csr_w_ena == 1'b1) && (csr_w_addr[11:10] != 2'b11) && (csr_w_addr == 12'h340)) begin	
			mscratch <= csr_w_data;
		end
		else begin
		end
	end

	//mhartid
	reg [`REG_BUS] 	mhartid;
	always @(posedge clk) 
	begin
		mhartid <= `ZERO_WORD;

	end

	//mimpid
	reg [`REG_BUS] 	mimpid;
	always @(posedge clk) 
	begin
		mimpid <= 64'b0000000000000110111111111100101111011101011111011000111000010111;

	end


	//read module, combinational
	assign mtvec_dest = {mtvec[63:2],2'b00};
	//assign mepc_dest = {mepc[63:2],2'b00};
	assign mepc_dest = mepc;

	always @(*) begin
		if (rst == 1'b1)
			csr_r_data = `ZERO_WORD;
		else if (csr_r_ena == 1'b1) begin
			case (csr_r_addr)
				12'hb00:
				begin 
					csr_r_data = mcycle;
				end
				12'h300:
				begin
					csr_r_data = mstatus;
				end
				12'h100:
				begin
					csr_r_data = sstatus;
				end
				12'h305:
				begin
					csr_r_data = mtvec;
				end
				12'h341:
				begin
					csr_r_data = mepc;
				end
				12'h342:
				begin
					csr_r_data = mcause;
				end
				12'h344:
				begin
					csr_r_data = mip;
				end
				12'h304:
				begin
					csr_r_data = mie;
				end
				12'h340:
				begin
					csr_r_data = mscratch;
				end
				12'hf14:
				begin
					csr_r_data = mhartid;
				end
				12'hf13:
				begin
					csr_r_data = mimpid;
				end
				default :
				begin
					csr_r_data = `ZERO_WORD;
				end
			endcase
		end
		else
			csr_r_data = `ZERO_WORD;
	end


endmodule
